//----------------------------------Include-------------------------------------
#include "mcu.h"
#include "glbvar.h"
//------------------------------------------------------------------------------

//ADC1 支持 11 个外部通道，ADC2 支持 13 个外部通道，ADC3 支持 15 个外部通道，ADC4 支持 13 个外部通道
//温度传感器连接到通道 ADC1_IN16
//VBAT/2 连接到通道 ADC1_IN17
//内部参照电压 VREFINT 连接到通道 ADCx_IN18 (VREFINT 典型值 1.20V (约 1490/0x5D2) 数据手册 45 页，表 4-7)
//VOP1OUT输出连接到通道 ADC1_IN3
//VOP2OUT输出连接到通道 ADC2_IN3
//VOP3OUT输出连接到通道 ADC3_IN1
//VOP4OUT输出连接到通道 ADC4_IN3
//ADC 内部通道可以按规则或者注入通道的方式进行转换
//温度传感器，VBAT/2 只能在主 ADC1 中使用

//-----------------------------------Macro--------------------------------------
#define _ADC_INST           ADC1
//------------------------------------------------------------------------------
#define _DMA_INST           DMA1
#define _DMA_EN             1
#define _DMA_CHN            DMA1_CH5
#define _DMA_NUM            5
//------------------------------------------------------------------------------
#define _SAMP_LEN           128
#define _ADC_VREF           (3.3)
//------------------------------------------------------------------------------
#define _CHN_N              (1)
//------------------------------------------------------------------------------

//--------------------------------Static Var------------------------------------
static uint16_t             nau16_ad_cache[_SAMP_LEN];
static uint16_t             nu16_temp;
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
#define Vc0        0           /*Vc0 is the ADC compensation value*/
#define Tc1        1.5f        /*Tc1 is the temprature compensation value*/
#define AVG_SLOPE  0.0041f
static  uint16_t   V30 = 0;    /*V30 is the voltage value at 30 degree Celsius by factory default*/ 
static float _TempCal(uint16_t TempAdVal)
{
  float Temperate;
  Temperate=((V30+Vc0-TempAdVal)*3.3/4095)/AVG_SLOPE+30.0f-Tc1;
  return Temperate;
}

static uint16_t _average(volatile uint16_t * p, uint32_t n)
{ 
  uint32_t i, sum=0;
  for(i=0; i<n; i++){
    sum += p[i];
  }
  return sum/n;
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
float mcu_get_temp(void)
{
  return _TempCal(nu16_temp);
}
//------------------------------------------------------------------------------
void mcu_init_adc(void)
{
//periph clock
  RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1, ENABLE);
  
//pin
  RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
  
  //PA1--ADC1_IN2--ADP   PA2--ADC12_IN11--ADN   PA3--ADC1_IN4--ADS
  GPIO_InitType     GPIO_InitS;
  GPIO_InitStruct (&GPIO_InitS);
  
  //SCLK/MOSI
  GPIO_InitS.Pin            = GPIO_PIN_3;
  GPIO_InitS.GPIO_Speed     = GPIO_Speed_2MHz;
  GPIO_InitS.GPIO_Mode      = GPIO_Mode_AIN;
  GPIO_InitPeripheral(GPIOA, &GPIO_InitS);
  
//adc
  RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSI, RCC_ADC1MCLK_DIV8);
  ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV16);
  
  //common
  ADC_InitType      ADC_InitS;
  ADC_InitStruct  (&ADC_InitS);
  
  ADC_InitS.MultiChEn      = DISABLE;   //scan
  ADC_InitS.ContinueConvEn = DISABLE;   //continuous
  ADC_InitS.ExtTrigSelect  = ADC_EXT_TRIGCONV_T3_TRGO;
  ADC_InitS.DatAlign       = ADC_DAT_ALIGN_R;
  ADC_InitS.ChsNumber      = 1;
  ADC_Init(_ADC_INST, &ADC_InitS);
  
  ADC_EnableExternalTrigConv(_ADC_INST, ENABLE);
  
  //TempSensor
  ADC_EnableTempSensorVrefint(ENABLE);
  V30 = *(__IO uint32_t*)((uint32_t)0x1FFFF7D0);
  
  //channel
  ADC_ConfigRegularChannel(_ADC_INST, ADC_CH_4, 1, ADC_SAMP_TIME_239CYCLES5);
  
  //enable
  ADC_Enable(_ADC_INST, ENABLE);
  while(!ADC_GetFlagStatusNew(_ADC_INST, ADC_FLAG_RDY));
  while(!ADC_GetFlagStatusNew(_ADC_INST, ADC_FLAG_PD_RDY));
      
#if _DMA_EN == 1
  ADC_EnableDMA(_ADC_INST, ENABLE);
  
  //periph clock
  RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);

  //dma
  DMA_InitType      DMA_InitS;
  DMA_StructInit  (&DMA_InitS);
  
  DMA_DeInit(_DMA_CHN);
  DMA_InitS.PeriphAddr     = (uint32_t)&_ADC_INST->DAT;
  DMA_InitS.MemAddr        = (uint32_t)nau16_ad_cache;
  DMA_InitS.Direction      = DMA_DIR_PERIPH_SRC;
  DMA_InitS.BufSize        = 0;
  DMA_InitS.PeriphInc      = DMA_PERIPH_INC_DISABLE;
  DMA_InitS.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
  DMA_InitS.PeriphDataSize = DMA_PERIPH_DATA_SIZE_HALFWORD;
  DMA_InitS.MemDataSize    = DMA_MemoryDataSize_HalfWord;
  DMA_InitS.CircularMode   = DMA_MODE_CIRCULAR;
  DMA_InitS.Priority       = DMA_PRIORITY_HIGH;
  DMA_InitS.Mem2Mem        = DMA_M2M_DISABLE;
  DMA_Init(_DMA_CHN, &DMA_InitS);
  
  //trigger
  DMA_RequestRemap(DMA1_REMAP_ADC1, _DMA_INST, _DMA_CHN, ENABLE);
  
  //interrupt
  DMA_ConfigInt(_DMA_CHN, DMA_INT_TXC, ENABLE);
  //NVIC
  NVIC_InitType    NVIC_InitS_DMA;
  NVIC_InitS_DMA.NVIC_IRQChannel                   = DMA1_Channel5_IRQn;
  NVIC_InitS_DMA.NVIC_IRQChannelPreemptionPriority = 3;
  NVIC_InitS_DMA.NVIC_IRQChannelSubPriority        = 3;
  NVIC_InitS_DMA.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitS_DMA);
  
//enable
  _DMA_INST->INTCLR = 0x0F<<((_DMA_NUM-1)*3);   //clear all flag
  DMA_SetCurrDataCounter(_DMA_CHN, _SAMP_LEN);
  DMA_EnableChannel(_DMA_CHN, ENABLE);
#endif
}
//------------------------------------------------------------------------------

//------------------------------------ISR---------------------------------------
void DMA1_Channel5_IRQHandler(void)
{
  if(_DMA_INST->INTSTS & (1<<((_DMA_NUM-1)*4+1)) ){   //DMA_GetIntStatus(DMA_INT_TXC1)
    _DMA_INST->INTCLR  = (1<<((_DMA_NUM-1)*4+1));     //DMA_ClrIntPendingBit(DMA_INT_TXC1)
    
    nu16_temp = _average(nau16_ad_cache, _SAMP_LEN);
  }
  
  if(_DMA_INST->INTSTS & (1<<((_DMA_NUM-1)*4+3)) ){   //err
    _DMA_INST->INTCLR  = (1<<((_DMA_NUM-1)*4+3));
  }
}
//------------------------------------EOF---------------------------------------







